package com.rivues.module.account.web.handler;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.rivues.core.RivuDataContext;
import com.rivues.core.RivuDataContext.ErrorMessageCode;
import com.rivues.module.platform.web.handler.Handler;
import com.rivues.module.platform.web.handler.ResponseData;
import com.rivues.module.platform.web.model.Cube;
import com.rivues.module.platform.web.model.CubeLevel;
import com.rivues.module.platform.web.model.CubeMeasure;
import com.rivues.module.platform.web.model.Dimension;
import com.rivues.module.platform.web.model.TableProperties;
import com.rivues.module.platform.web.model.TableTask;
import com.rivues.module.platform.web.model.User;
import com.rivues.util.RivuTools;
import com.rivues.util.iface.cube.CubeFactory;
import com.rivues.util.realm.TrustedSSOAuthenticationToken;
  
@Controller  
@RequestMapping("/{orgi}")  
public class LoginController extends Handler{  
	private final Logger log = LoggerFactory.getLogger(LoginController.class); 
	/** 
     * 用户登录 
     *  //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查  
        //每个Realm都能在必要时对提交的AuthenticationTokens作出反应  
        //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法  
     */  
    @RequestMapping(value="/login", name="get_login" , type="userauth",subtype="userauth",method=RequestMethod.GET)  
    public ModelAndView login(HttpServletRequest request , @PathVariable String orgi){  
    	ResponseData responseData = new ResponseData("redirect:/{orgi}/user/index.html") ; 
    	//获取当前的Subject  
        Subject currentUser = SecurityUtils.getSubject();
        if(!currentUser.isAuthenticated()){
        	responseData = new ResponseData("/pages/login") ; 
        }
    	return request(responseData , orgi) ; 
    }
    /** 
     * 用户登录 
     *  //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查  
        //每个Realm都能在必要时对提交的AuthenticationTokens作出反应  
        //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法  
     */  
    @RequestMapping(value="/login",name="post_login" , type="userauth",subtype="userauth", method=RequestMethod.POST)  
    public ModelAndView login(HttpServletRequest request , @PathVariable String orgi, @Valid User user , @RequestHeader(value = "referer", required = false) final String referer){  
    	ResponseData responseData = new ResponseData("redirect:/{orgi}/user/index.html") ; 
    	TrustedSSOAuthenticationToken token = new TrustedSSOAuthenticationToken(user.getUsername(), user.getPassword() , orgi);  
//    	UsernamePasswordToken token = new UsernamePasswordToken(request.getParameter("username"), request.getParameter("password"));
    	token.setRememberMe(true);  
        //获取当前的Subject  
        Subject currentUser = SecurityUtils.getSubject(); 
        ErrorMessageCode error = null ;
        try {  
        	List<User> users = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(User.class).add(Restrictions.eq("password",RivuTools.md5(user.getPassword()))).add(Restrictions.eq("username",user.getUsername())).add(Restrictions.eq("orgi",orgi)));
    		if(users.size()>0){  
    			currentUser.login(token);   	
            }else{
            	throw new AuthenticationException();
            }
    		
        }catch(UnknownAccountException uae){  
        	error = RivuDataContext.ErrorMessageCode.ERR_1000000 ;  
            info("对用户[" + token.getUsername() + "]进行登录验证..验证未通过,"+RivuDataContext.ErrorMessageCode.ERR_1000000.getText());  
        }catch(IncorrectCredentialsException ice){  
            info("对用户[" + token.getUsername() + "]进行登录验证..验证未通过,错误的凭证");  
            error = RivuDataContext.ErrorMessageCode.ERR_1000001 ;  
        }catch(LockedAccountException lae){  
        	info("对用户[" + token.getUsername() + "]进行登录验证..验证未通过,账户已锁定");  
        	error = RivuDataContext.ErrorMessageCode.ERR_1000002;  
        }catch(ExcessiveAttemptsException eae){  
        	info("对用户[" + token.getUsername() + "]进行登录验证..验证未通过,错误次数过多");  
        	error = RivuDataContext.ErrorMessageCode.ERR_1000003;  
        }catch(AuthenticationException ae){  
        	ae.printStackTrace();
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景  
        	info("对用户[" + token.getUsername() + "]进行登录验证..验证未通过,堆栈轨迹如下");  
            error = RivuDataContext.ErrorMessageCode.ERR_1000004;  
        }  
        //验证是否登录成功  
        if(!currentUser.isAuthenticated()){  
            responseData = new ResponseData("/pages/login") ; 
        }else{
        	request.getSession().setAttribute(RivuDataContext.USER_SESSION_NAME , SecurityUtils.getSubject().getSession().getAttribute(RivuDataContext.USER_SESSION_NAME)) ;
        }
        ModelAndView view = request(responseData , orgi) ;
        if(error!=null){
        	view.addObject("error", error) ;
        }
        return view ;
    }  

	/** 
     * 用户登出 
     */  
    @RequestMapping("/logout")  
    public ModelAndView logout(HttpServletRequest request  , @PathVariable String orgi){  
    	request.getSession().removeAttribute(RivuDataContext.USER_SESSION_NAME) ;
//        SecurityUtils.getSubject().logout();  
//         request.getSession().removeAttribute(RivuDataContext.USER_SESSION_NAME) ;
         return request(new ResponseData("redirect:/{orgi}/login.html") , orgi) ;
    }  
    /**
     * 密码修改
     * @param request
     * @param orgi
     * @return
     */
    @RequestMapping(value="/passwordupdate", name="passwordupdate" , type="passwordupdate",subtype="passwordupdate")  
    public ModelAndView passwordupdate(HttpServletRequest request , @PathVariable String orgi){  
    	ModelAndView view = request(super.createManageResponse("/pages/passwordupdate") , orgi) ;
    	view.addObject("username", request.getParameter("username"));
    	return view ; 
    }
    
    
    @RequestMapping(value="/passwordupdatedo", name="passwordupdatedo" , type="passwordupdatedo",subtype="passwordupdatedo")  
    public ModelAndView passwordupdatedo(HttpServletRequest request , @PathVariable String orgi,@Valid String username,@Valid String oldpassword,@Valid String newpassword){  
    	ResponseData responseData = new ResponseData("redirect:/{orgi}/login.html?msgcode=S_LOGIN_000001");
    	List<User> users = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(User.class).add(Restrictions.eq("password",RivuTools.md5(oldpassword))).add(Restrictions.eq("username",username)).add(Restrictions.eq("orgi",orgi)));
    	if(users.size()>0){
    		User user = users.get(0);
    		user.setPassupdatetime(new Date());
    		user.setPassword(RivuTools.md5(newpassword));
    		super.getService().updateIObject(user);
    	}else{
    		responseData.setPage("redirect:/{orgi}/login.html?msgcode=E_LOGIN_000001");
    	}
    	ModelAndView view = request(responseData , orgi) ;
    	
    	return view ; 
    }
    
    /**
     * 验证密码是否超过设置期限
     * @param request
     * @param orgi
     * @return
     */
    @RequestMapping(value="/checkpassword", name="checkpassword" , type="checkpassword",subtype="checkpassword")  
    public ModelAndView checkpassword(HttpServletRequest request , @PathVariable String orgi,@Valid User user){  
    	ModelAndView view = request(super.createManageResponse("/pages/public/success") , orgi) ;
    	List<User> users = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(User.class).add(Restrictions.eq("password",RivuTools.md5(user.getPassword()))).add(Restrictions.eq("username",user.getUsername())).add(Restrictions.eq("orgi",orgi)));
    	if(users.size()>0){
    		Date updateDate = users.get(0).getPassupdatetime();
    		Calendar calendar = Calendar.getInstance();
    		calendar.add(Calendar.MONTH,-6); 
    		if(updateDate==null||(calendar.getTimeInMillis()>=updateDate.getTime())){//过期
    			view.addObject("data", "no");
    		}else{
    			view.addObject("data", "yes");
    		}
    		
    	}else{
    		view.addObject("data", "username or password is wrong!");
    	}
    	
    	return view ; 
    }
    
    
    /** 
     * 临时方法（结算任务表补充原始表名称以及字段的原始名称）  
     */  
    @RequestMapping(value="/tabletask",name="tabletask" , type="tabletask",subtype="tabletask")  
    public ModelAndView tabletask(HttpServletRequest request , @PathVariable String orgi, @Valid User user , @RequestHeader(value = "referer", required = false) final String referer){  
    	ResponseData responseData = new ResponseData("redirect:/{orgi}/user/index.html") ; 
        ModelAndView view = request(responseData , orgi) ;
        
        List<TableTask> tables = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(TableTask.class).add(Restrictions.like("name","C_D_",MatchMode.START)).add(Restrictions.eq("orgi",orgi)));
        List<Cube> cubes = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(Cube.class).add(Restrictions.eq("orgi",orgi)));
        for (TableTask table : tables) {
			if(StringUtils.isBlank(table.getGroupid())){
				for (Cube cube : cubes) {
					cube = super.loadCubeData(orgi, (Cube) super.getService().getIObjectByPK(Cube.class, cube.getId()), true) ;
					if(cube.getTable().equals(table.getName())){
						table.setGroupid(CubeFactory.getCubeInstance().getJobNameByCubeDic(cube.getTypeid(),cube.getOrgi())+"/"+cube.getName());
						super.getService().updateIObject(table);
						List<TableProperties> propers = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(TableProperties.class).add(Restrictions.eq("dbtableid",table.getId())));
						for (TableProperties proper : propers) {
							if("R3_CUBE_DATA_VERSION".equals(proper.getName())){
								proper.setGroupid("R3_CUBE_DATA_VERSION");
							}
							if("R3_CUBE_DATA_ID".equals(proper.getName())){
								proper.setGroupid("R3_CUBE_DATA_ID");
							}
							if(proper.getName().startsWith("MEA_")){//处理指标
								List<CubeMeasure> measures = cube.getMeasure();
								for (CubeMeasure measure : measures) {
									if(proper.getName().equals("MEA_"+measure.getNameAlias().toUpperCase())){
										proper.setGroupid(measure.getCode());
										break;
									}
								}
							}
							if(proper.getName().startsWith("DIM_")){//处理维度成员
								List<Dimension> dims = cube.getDimension();
								
								for (Dimension dim : dims) {
									List<CubeLevel> levels = dim.getCubeLevel();
									for (CubeLevel Level : levels) {
										if(proper.getName().equals("DIM_"+Level.getNameAlias().toUpperCase())){
											proper.setGroupid(Level.getCode());
											break;
										}
									}
								}
							}
							super.getService().updateIObject(proper);
						}
						break;
					}
				}
			}else{
				System.out.println("已存在："+table.getGroupid());
			}
		}
        return view ;
    }  
} 